package com.sl.plugin.step.field;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.sl.core.engine.check.ProcessCompCheckParam;
import com.sl.core.engine.check.ProcessCompCheckResult;
import com.sl.core.engine.meta.ProcessCompDescriptorService;
import com.sl.core.engine.meta.impl.AbstractProcessCompDescriptor;
import com.sl.core.engine.meta.row.ProcessRowDescriptor;
import com.sl.core.engine.meta.valuemeta.ValueMetaArray;
import com.sl.core.engine.meta.valuemeta.ValueMetaObject;
import lombok.Getter;
import org.apache.commons.compress.utils.Lists;
import org.apache.hop.core.row.IValueMeta;
import org.noear.snack.ONode;

import java.util.Collections;
import java.util.List;
import java.util.Map;

//@Comp(id = "ManyToOne", name = "多行转一行", desc = "多行转一行", groupName = "转换")
@Getter
public class FieldSplitCompDescriptor extends AbstractProcessCompDescriptor<
        FieldSplitComp, FieldSplitCompContext> implements ProcessCompDescriptorService {


    @Override
    public void loadDescriptor(Map<String, Object> map) {

    }

    @Override
    public List<ProcessCompCheckResult> check(ProcessCompCheckParam processCompCheckParam) {
        return checkWrapper(checkOnlyOneInput(processCompCheckParam));
    }


    @Override
    public ProcessRowDescriptor getResultDescriptor(ProcessRowDescriptor rowDescriptor) {


        Boolean jsonSplitFlag = getBoolAttr("config.jsonSplitFlag");
        if (BooleanUtil.isTrue(jsonSplitFlag)) {
            List<IValueMeta> iValueMetas = jsonSplitBy(rowDescriptor.getValueMetaList());
            return new ProcessRowDescriptor(iValueMetas);
        }
        Boolean levelSplitFlag = getBoolAttr("config.levelSplitFlag");
        Integer level = getIntAttr("config.level");
        if (BooleanUtil.isTrue(levelSplitFlag) && ObjectUtil.isNotNull(level)) {
            List<IValueMeta> iValueMetas = levelSplitBy(rowDescriptor.getValueMetaList(), 0, level);
            return new ProcessRowDescriptor(iValueMetas);
        }

        Boolean jsonPathSplitFlag = getBoolAttr("config.jsonPathSplitFlag");
        String jsonPath = getStrAttr("config.jsonPath");
        if (BooleanUtil.isTrue(jsonPathSplitFlag) && StrUtil.isNotBlank(jsonPath)) {
            ProcessRowDescriptor iValueMetas = jsonPathSplitBy(rowDescriptor, jsonPath);

            return iValueMetas;
        }
        return new ProcessRowDescriptor(rowDescriptor);
    }

    private ProcessRowDescriptor jsonPathSplitBy(ProcessRowDescriptor rowDescriptor, String jsonPath) {

        //表达式替换
        String replace = StrUtil.replace(jsonPath, "\\[.*?\\]", "*");

        Object o = rowDescriptor.mockValue();

        ONode oNode = ONode.loadObj(o);

        Object value = oNode.select(replace).toObject();

        ProcessRowDescriptor ro = rowDescriptor.convertMetaI(value);
        if (ObjectUtil.isNull(ro)) {
            return new ProcessRowDescriptor();
        }
        return ro;

    }


    private List<IValueMeta> levelSplitBy(List<IValueMeta> valueMetaList, Integer level, Integer maxLevel) {
        if (CollUtil.isEmpty(valueMetaList)) {
            return Collections.emptyList();
        }
        ++level;
        List<IValueMeta> result = Lists.newArrayList();
        for (IValueMeta valueMeta : valueMetaList) {

            if (valueMeta instanceof ValueMetaArray valueMetaArray) {
                List<IValueMeta> fields = valueMetaArray.getFields();
                IValueMeta fieldType = valueMetaArray.getFieldType();
                List<IValueMeta> iValueMetas = Lists.newArrayList();
                if (fieldType instanceof ValueMetaObject) {
                    List<IValueMeta> im = levelSplitBy(fields, level, maxLevel);
                    List<IValueMeta> cc = Lists.newArrayList();
                    for (IValueMeta iValueMeta : im) {
                        if (iValueMeta instanceof ValueMetaArray) {
                            cc.add(iValueMeta);
                            continue;
                        }
                        ValueMetaArray iValueMeta1 = new ValueMetaArray();
                        iValueMeta1.setFieldType(iValueMeta);
                        iValueMeta1.setName(iValueMeta.getName());
                        cc.add(iValueMeta1);
                    }
                    iValueMetas.addAll(cc);
                } else {
                    if (level.equals(maxLevel)) {
                        iValueMetas.add(valueMetaArray);
                    }

                }

                if (CollUtil.isNotEmpty(iValueMetas)) {
                    result.addAll(iValueMetas);
                }
            } else if (valueMeta instanceof ValueMetaObject valueMetaObject) {
                List<IValueMeta> fields = valueMetaObject.getFields();
                List<IValueMeta> iValueMetas = levelSplitBy(fields, level, maxLevel);
                if (CollUtil.isNotEmpty(iValueMetas)) {
                    result.addAll(iValueMetas);
                }
            } else {
                if (level.equals(maxLevel)) {
                    result.add(valueMeta);
                }
            }
        }

        return result;
    }

    private List<IValueMeta> jsonSplitBy(List<IValueMeta> valueMetaList) {

        List<IValueMeta> result = Lists.newArrayList();

        for (IValueMeta valueMeta : valueMetaList) {
            if (valueMeta instanceof ValueMetaObject valueMetaObject) {
                List<IValueMeta> fields = valueMetaObject.getFields();
                List<IValueMeta> iValueMetas = jsonSplitBy(fields);
                if (CollUtil.isNotEmpty(iValueMetas)) {
                    result.addAll(iValueMetas);
                }
            } else if (valueMeta instanceof ValueMetaArray valueMetaArray) {
                List<IValueMeta> fields = valueMetaArray.getFields();
                IValueMeta fieldType = valueMetaArray.getFieldType();
                List<IValueMeta> iValueMetas = Lists.newArrayList();
                if (fieldType instanceof ValueMetaObject) {
                    List<IValueMeta> im = jsonSplitBy(fields);

                    List<IValueMeta> cc = Lists.newArrayList();
                    for (IValueMeta iValueMeta : im) {
                        if (iValueMeta instanceof ValueMetaArray) {
                            cc.add(iValueMeta);
                            continue;
                        }
                        ValueMetaArray iValueMeta1 = new ValueMetaArray();
                        iValueMeta1.setFieldType(iValueMeta);
                        iValueMeta1.setName(iValueMeta.getName());
                        cc.add(iValueMeta1);
                    }
                    iValueMetas.addAll(cc);
                } else {
                    iValueMetas.add(valueMetaArray);
                }

                if (CollUtil.isNotEmpty(iValueMetas)) {
                    result.addAll(iValueMetas);
                }
            } else {
                result.add(valueMeta);
            }
        }
        return result;
    }

}
